<?php
/********************************************************************
 *	Author:
 *		Jestery Liu <jestery@gmail.com>
 *		http://www.pte.cn
 *
 *	File:			Uploader.class.php
 *	Create Date:	2007-02-14 22:22:47 CST
 *******************************************************************/

require_once(PTE::getCoreLibsPath().'FileSpec.class.php');

class FileUploader extends FileSpec
{
	const ERROR_NON_UPLOADED = -2;
	const ERROR_CANNOT_MOVE = -3;
	const ERROR_REMOTE = -4;
	const ERROR_LOCAL_FILE = -5;
	const ERROR_EXTENSION_NOT_ALLOWED = -6;
	const ERROR_INVALID_URL = -7;

	protected $destPath;
	protected $destFile;
	protected $dest;
	protected $allowedExtensions = array();

	public function __construct($field = null)
	{
		if ($field!=null)
		{
			$this->parse($field);
		}
	}

	public function setFile($field)
	{
		$this->parse($field);
	}

	public function setDestPath($path)
	{
		$this->destPath = $path;
	}

	public function setDestFile($filename, $useOrigExtension=true)
	{
		if ($useOrigExtension)
			$this->destFile = $filename.$this->extension;
		else
			$this->destFile = $filename;
	}

	public function setAllowedExtensions(array $exts)
	{
		$this->allowedExtensions = $exts;
	}

	public function getAllowedExtensions()
	{
		return $this->allowedExtensions;
	}

	public function extensionIsAllowed()
	{
		return in_array($this->extension, $this->allowedExtensions);
	}

	protected function removeTempFile()
	{
		@unlink($this->filename);
		return true;
	}

	protected function returnCode($code)
	{
		$this->removeTempFile();
		return $code;
	}

	protected function isUploaded()
	{
		return is_uploaded_file($this->filename) && file_exists($this->filename);
	}

	protected function preUpload($checkExtension=false, $checkIfIsUploaded=false)
	{
		if (empty($this->destPath) || empty($this->destFile))
		{
			$this->removeTempFile();
			throw new UploaderException("destPath and/or destFile doesn't set.");
		}
		if ($checkExtension)
		{
			if (!$this->extensionIsAllowed())
				return $this->returnCode(self::ERROR_EXTENSION_NOT_ALLOWED);
		}
		if ($checkIfIsUploaded)
		{
			if (!$this->isUploaded())
				return $this->returnCode(self::ERROR_NON_UPLOADED);
		}
		$sp = substr($this->destPath, -1,1);
		if ($sp=='/' || $sp=='\\')
			$this->dest = $this->destPath.$this->destFile;
		else
			$this->dest = $this->destPath.'/'.$this->destFile;
		return true;
	}

	protected function formUpload($mode, $checkExtension, $checkIfIsUploaded=false)
	{
		$code = $this->preUpload($checkExtension, $checkIfIsUploaded);
		if ($code<0)
			return $code;
		if (!@move_uploaded_file($this->filename, $this->dest))
			return $this->returnCode(self::ERROR_CANNOT_MOVE);
		@chmod($this->dest, $mode);
		return $this->returnCode(true);
	}

	protected function remoteUpload($mode, $checkExtension, $bufferSize)
	{
		$code = $this->preUpload($checkExtension, false);
		if ($code<0)
			return $code;
		$src = @fopen($this->url, 'rb');
		if (!$src)
			return self::ERROR_REMOTE;
		$dest = @fopen($this->dest, 'wb');
		if (!$dest)
			return self::ERROR_LOCAL_FILE;
		while(stream_copy_to_stream($src, $dest, $bufferSize)!==0);
		$this->mimetype = $this->_getMimetype($this->dest);
		@chmod($this->dest, $mode);
		return true;
	}
}

class Uploader extends FileUploader
{
	public function __construct($field = null)
	{
		parent::__construct($field);
	}

	public function upload($mode=0644, $checkExtension = true, $bufferSize=16384)
	{
		$code = $this->isRemote ? 
				$this->remoteUpload($mode, $checkExtension, $bufferSize) : 
				$this->formUpload($mode, $checkExtension);
		return $code > 0 ? $this->dest : $code;
	}
}

class UploaderException extends Exception {
	public function __construct($message, $code=0) {
		parent::__construct($message, $code);
	}
}
/* vim: set ts=4 sw=4 ff=unix: */
